
package cartagows.wsframework.wssecurity.policy.builders;

import java.util.Iterator;
import java.util.List;

import javax.xml.namespace.QName;

import org.apache.axiom.om.OMElement;
import org.apache.neethi.Assertion;
import org.apache.neethi.AssertionBuilderFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.neethi.builders.AssertionBuilder;
import org.apache.neethi.builders.xml.XmlPrimtiveAssertion;

import cartagows.wsframework.wssecurity.policy.SP11Constants;
import cartagows.wsframework.wssecurity.policy.SPConstants;
import cartagows.wsframework.wssecurity.policy.model.AlgorithmSuite;
import cartagows.wsframework.wssecurity.policy.model.SignedEncryptedElements;
import cartagows.wsframework.wssecurity.policy.model.SignedEncryptedParts;
import cartagows.wsframework.wssecurity.policy.model.SupportingToken;
import cartagows.wsframework.wssecurity.policy.model.Token;

public class SupportingTokensBuilder implements AssertionBuilder {

    public Assertion build(OMElement element, AssertionBuilderFactory factory)
            throws IllegalArgumentException {
        QName name = element.getQName();
        SupportingToken supportingToken = null;

        if (SP11Constants.SUPPORTING_TOKENS.equals(name)) {
            supportingToken = new SupportingToken(SPConstants.SUPPORTING_TOKEN_SUPPORTING, SPConstants.SP_V11);
        } else if (SP11Constants.SIGNED_SUPPORTING_TOKENS.equals(name)) {
            supportingToken = new SupportingToken(SPConstants.SUPPORTING_TOKEN_SIGNED, SPConstants.SP_V11);
        } else if (SP11Constants.ENDORSING_SUPPORTING_TOKENS.equals(name)) {
            supportingToken = new SupportingToken(SPConstants.SUPPORTING_TOKEN_ENDORSING, SPConstants.SP_V11);
        } else if (SP11Constants.SIGNED_ENDORSING_SUPPORTING_TOKENS.equals(name)) {
            supportingToken = new SupportingToken(SPConstants.SUPPORTING_TOKEN_SIGNED_ENDORSING, SPConstants.SP_V11);
        }

        Policy policy = PolicyEngine.getPolicy(element.getFirstElement());
        policy = (Policy) policy.normalize(false);

        for (Iterator iterator = policy.getAlternatives(); iterator.hasNext();) {
            processAlternative((List) iterator.next(), supportingToken);
            /*
             * for the moment we will say there should be only one alternative 
             */
            break;            
        }

        return supportingToken;
    }

    public QName[] getKnownElements() {
        return new QName[] {  SP11Constants.SUPPORTING_TOKENS,
                SP11Constants.SIGNED_SUPPORTING_TOKENS,
                SP11Constants.ENDORSING_SUPPORTING_TOKENS,
                SP11Constants.SIGNED_ENDORSING_SUPPORTING_TOKENS};
    }

    private void processAlternative(List assertions, SupportingToken supportingToken) {
        
        for (Iterator iterator = assertions.iterator(); iterator.hasNext();) {

            Assertion primitive = (Assertion) iterator.next();
            QName qname = primitive.getName();

            if(primitive.getName().getLocalPart().equals("UsernameToken")){
            	UsernameTokenBuilder utb = new UsernameTokenBuilder();
            	primitive = utb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
            }
            if(primitive.getName().getLocalPart().equals("X509Token")){
            	X509TokenBuilder xtb = new X509TokenBuilder();
            	primitive = xtb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
            }
            
            if (SP11Constants.ALGORITHM_SUITE.equals(qname)) {
            	AlgorithmSuiteBuilder asb = new AlgorithmSuiteBuilder();
				primitive = asb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
                supportingToken.setAlgorithmSuite((AlgorithmSuite) primitive);

            } else if (SP11Constants.SIGNED_PARTS.equals(qname)) {
            	SignedPartsBuilder spb = new SignedPartsBuilder();
				primitive = spb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
                supportingToken.setSignedParts((SignedEncryptedParts) primitive);

            } else if (SP11Constants.SIGNED_ELEMENTS.equals(qname)) {
            	SignedElementsBuilder seb = new SignedElementsBuilder();
				primitive = seb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
                supportingToken.setSignedElements((SignedEncryptedElements) primitive);

            } else if (SP11Constants.ENCRYPTED_PARTS.equals(qname)) {
            	EncryptedPartsBuilder epb = new EncryptedPartsBuilder();
				primitive = epb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
                supportingToken.setEncryptedParts((SignedEncryptedParts) primitive);

            } else if (SP11Constants.ENCRYPTED_ELEMENTS.equals(qname)) {
            	EncryptedElementsBuilder eeb = new EncryptedElementsBuilder();
				primitive = eeb.build(((XmlPrimtiveAssertion ) primitive).getValue(), null);
            	
                supportingToken.setEncryptedElements((SignedEncryptedElements) primitive);

            } else if (primitive instanceof Token) {
                supportingToken.addToken((Token) primitive);
            }
        }
    }
}
